/*
 *  AbstractSection.cpp
 *  SoundController0002
 *
 *  Created by jiro on 11/10/03.
 *  Copyright 2011 jiro music. All rights reserved.
 *
 */

#include "AbstractRegion.h"
#include "ConcreteNote.h"
#include "ConcreteLine.h"

namespace sc
{
namespace system0039
{
	void AbstractRegion::AddLine( const AbstractLine& line )
	{
		lines.push_back( line );
	}

	void AbstractRegion::Clear()
	{
		lines.clear();
	}

	int AbstractRegion::GetConcreteRegionCount() const
	{
		const int lineCount = lines.size();
		int totalRegionCount = 1;
		for ( int i = 0; i < lineCount; i++ )
		{
			const AbstractLine& line = lines[ i ];
			ConcreteLine concreteLine;
			int count = line.GetConcreteLineCount();
			totalRegionCount *= count;
		}
		return totalRegionCount;
	}

	void AbstractRegion::GetConcreteRegion( int index, Alignment alignment, ConcreteRegion& region ) const
	{
		//	initialize
		const int lineCount = lines.size();
		std::vector< int > indexList( lineCount );
		std::vector< std::vector< ConcreteLine > > concreteLinesList( lineCount );
		for ( int i = 0; i < lineCount; i++ )
		{
			const AbstractLine& line = lines[ i ];
			std::vector< ConcreteLine >& concreteLines = concreteLinesList[ i ];
			line.GetConcreteLines( concreteLines );
			indexList[ i ] = 0;
		}

		//	calc index
		int regionIndex = 0;
		bool isContinue = true;
		const int lastIndex = lineCount - 1;
		for ( int i = 0; i < index; i++ )
		{
			//	update index
			int indexIndex = lastIndex;
			indexList[ lastIndex ]++;
			while ( indexList[ indexIndex ] == concreteLinesList[ indexIndex ].size() )
			{
				if ( indexIndex == 0 )
				{
					isContinue = false;
					break;
				}

				indexList[ indexIndex ] = 0;
				indexIndex--;
				indexList[ indexIndex ]++;
			}
			if ( not isContinue )
			{
				break;
			}
			regionIndex++;
		}

		//	calc line duration
		double maxDuration = 0.0;
		for ( int j = 0; j < lineCount; j++ )
		{
			const ConcreteLine& line = concreteLinesList[ j ].at( indexList[ j ] );
			double duration = line.GetDuration();
			if ( duration > maxDuration )
			{
				maxDuration = duration;
			}
		}

		//	calc padding duration
		for ( int j = 0; j < lineCount; j++ )
		{
			ConcreteLine& line = concreteLinesList[ j ].at( indexList[ j ] );
			double duration, frequency;
			switch( alignment )
			{
			case LeftAlignment:
				break;

			case CenterAlignment:
				duration = ( maxDuration - line.GetDuration() ) / 2.0;
				frequency = 440;
				line.insert( line.begin(), ConcreteNote( frequency, 0.0, frequency + duration, 0.0 ) );
				break;

			case RightAlignment:
				duration = ( maxDuration - line.GetDuration() );
				frequency = 440;
				line.insert( line.begin(), ConcreteNote( frequency, 0.0, frequency + duration, 0.0 ) );
				break;
			}
		}

		//	add line
		for ( int j = 0; j < lineCount; j++ )
		{
			region.push_back( concreteLinesList[ j ].at( indexList[ j ] ) );
		}
	}

	std::string AbstractRegion::ToString( int tabCount ) const
	{
		std::stringstream ss;
		for ( int i = 0; i < tabCount; i++ )
		{
			ss << "\t";
		}
		
		ss << "AbstractRegion: \n";
		for ( int i = 0, count = lines.size(); i < count; i++ )
		{
			ss << lines[ i ].ToString( tabCount + 1 ) << "\n";
		}
		return ss.str();
	}

}
}
